#pragma once
#include "execution_defs.h"
#include "execution_manager.h"
#include "executor_abstract.h"
#include "index/ix.h"
#include "system/sm.h"

class UpdateExecutor : public AbstractExecutor {
   private:
    TabMeta tab_;
    std::vector<Condition> conds_;
    RmFileHandle *fh_;
    std::vector<Rid> rids_;
    std::string tab_name_;
    std::vector<SetClause> set_clauses_;
    SmManager *sm_manager_;

   public:
    UpdateExecutor(SmManager *sm_manager, const std::string &tab_name, std::vector<SetClause> set_clauses,
                   std::vector<Condition> conds, std::vector<Rid> rids, Context *context) {
        sm_manager_ = sm_manager;
        tab_name_ = tab_name;
        set_clauses_ = set_clauses;
        tab_ = sm_manager_->db_.get_table(tab_name);
        fh_ = sm_manager_->fhs_.at(tab_name).get();
        conds_ = conds;
        rids_ = rids;
        context_ = context;
    }
    std::unique_ptr<RmRecord> Next() override {
        // 通过获取所有必要的索引句柄、遍历每个要更新的记录标识符（RID）来完成更新操作。
        // 获取所有必要的索引文件的句柄
        std::vector<IxIndexHandle *> ihs(tab_.cols.size(), nullptr);
        for (auto &set_clause : set_clauses_) {
            auto lhs_col = tab_.get_col(set_clause.lhs.col_name);// 获取要设置的列
            if (lhs_col->index) {
                size_t lhs_col_idx = lhs_col - tab_.cols.begin();// 获取索引列的索引
                // lab3 task3 Todo
                // 获取需要的索引句柄,填充vector ihs
                // lab3 task3 Todo end
                ihs[lhs_col_idx] = sm_manager_->ihs_.at(sm_manager_->get_ix_manager()->get_index_name(tab_name_, lhs_col_idx)).get();// 获取对应列的索引句柄
            }
        }
        // 更新每个RID的记录文件和索引文件
        for (auto &rid : rids_) {
            auto rec = fh_->get_record(rid, context_);// 获取要更新的记录
            // lab3 task3 Todo
            // Remove old entry from index
            // lab3 task3 Todo end
            for (long unsigned int i = 0; i < tab_.cols.size(); i++)
            {
                if (tab_.cols[i].index)
                {
                    auto ifh = sm_manager_->ihs_.at(sm_manager_->get_ix_manager()->get_index_name(tab_name_, i)).get();// 获取索引文件句柄
                    ifh->delete_entry(rec->data + tab_.cols[i].offset,context_->txn_);// 从索引中删除对应的条目
                }
            }

            // 记录更新操作到事务中
            RmRecord update_record{rec->size};
            memcpy(update_record.data, rec->data, rec->size);

            // lab3 task3 Todo
            // Update record in record file
            // lab3 task3 Todo end

            // 更新记录文件中的记录
            for (auto &set_clause : set_clauses_) {
                auto lhs_col = tab_.get_col(set_clause.lhs.col_name);// 获取要设置的列
                memcpy(rec->data + lhs_col->offset, set_clause.rhs.raw->data, lhs_col->len);// 将新值复制到记录的相应位置
            }
            fh_->update_record(rid, rec->data, context_);// 更新记录文件中的记录

            // lab3 task3 Todo
            // Insert new entry into index
            // lab3 task3 Todo end
            for (long unsigned int i = 0; i < tab_.cols.size(); i++)// 将新条目插入索引中
            {
                if (tab_.cols[i].index)
                {
                    auto ifh = sm_manager_->ihs_.at(sm_manager_->get_ix_manager()->get_index_name(tab_name_, i)).get();// 获取索引文件句柄
                    ifh->insert_entry(rec->data + tab_.cols[i].offset,rid,context_->txn_);// 将新的记录数据插入索引
                }
            }
        }
        return nullptr;
    }
    Rid &rid() override { return _abstract_rid; }
};